package net.butfly.bus.server;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.butfly.bus.TX;
import net.butfly.bus.config.bean.FilterBean;
import net.butfly.bus.config.bean.NodeBean;
import net.butfly.bus.config.bean.RouterBean;
import net.butfly.bus.config.bean.TimeoutBean;
import net.butfly.bus.config.bean.TxBean;
import net.butfly.bus.context.Constants;
import net.butfly.bus.exception.BusRuntimeException;
import net.butfly.bus.server.config.impl.ConfigXmlImp;
import net.butfly.bus.util.LogUtils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class ServerConfig {
	private static LogUtils logger = LogUtils.getLog();

	private final static String configFileName = "bus-server.xml";

	private static Document configDoc;

	private static ServerConfigInterface ins;

	// -------------------------------------------------------------------------
	private static List<FilterBean> filterBeanList;

	private static String runMode = "deploy";

	private static String mode = "normal";

	private static String simulateDir;

	private static String txAnnotation;

	private static String defaultErrorCode;

	// -------------------------------------------------------------------------
	private static enum Type {
		localXml, remoteHessian
	}

	private ServerConfig() {}

	@SuppressWarnings("unchecked")
	public static void init() {
		try {
			URL url = Thread.currentThread().getContextClassLoader().getResource(configFileName);
			if (url == null) {
				url = ServerConfig.class.getResource(configFileName);
			}
			configDoc = url != null ? new SAXReader().read(url) : null;
			if (configDoc != null) {
				logger.info("begin to analyze configuration file " + url + ".");
				Element ele = (Element) configDoc.getRootElement().selectSingleNode("ebox-mode");
				mode = ele != null ? ele.getTextTrim() : mode;
				logger.info("bus running in mode: " + mode + ".");

				ele = (Element) configDoc.getRootElement().selectSingleNode("simulate-dir");
				simulateDir = ele != null ? ele.getTextTrim() : null;
				if (simulateDir != null) {
					logger.info("simmulate XML file in path: " + simulateDir
							+ (!isSimulate() ? "(will not be applied in normal mode)" : "") + ".");
				}
				// -----------------------------------------------------------------------------------解析runMode
				ele = (Element) configDoc.getRootElement().selectSingleNode("run-mode");
				runMode = ele != null ? ele.getTextTrim() : runMode;
				logger.info("bus mode: " + runMode + ".");
				// -----------------------------------------------------------------------------------解析txAnnotation
				ele = (Element) configDoc.getRootElement().selectSingleNode("tx-annotation");
				txAnnotation = ele != null ? ele.getTextTrim() : null;
				if (txAnnotation != null) {
					logger.info("bus will analyze customized annotations " + txAnnotation
							+ " and default annotations net.butfly.bus.TX");
				} else {
					logger.info("bus will analyze default annotations net.butfly.bus.TX.");
				}
				// -----------------------------------------------------------------------------------解析defaultErrorCode
				ele = (Element) configDoc.getRootElement().selectSingleNode("default-error-code");
				defaultErrorCode = ele != null ? ele.getTextTrim() : null;
				if (defaultErrorCode != null) {
					logger.info("bus will return error code of " + defaultErrorCode
							+ " on business invoking successed.");
				}
				// -----------------------------------------------------------------------------------解析filter
				filterBeanList = new ArrayList<FilterBean>();
				List<Element> eleList = configDoc.getRootElement().selectNodes("filter");
				if (eleList != null) {
					int order = -1;
					Map<String, String> initParamMap = null;
					for (Element tEle : eleList) {
						String title = tEle.attributeValue("title");
						if (tEle.attributeValue("enabled") == null
								|| tEle.attributeValue("enabled").trim().toUpperCase().equals("TRUE")) {
							String ts = tEle.attributeValue("order");
							if (ts != null) {
								ts = ts.toUpperCase();
								order = (ts.toUpperCase().startsWith("B") ? -1 : 1)
										* Integer.valueOf((ts.substring(1)));
							}
							List<Element> paramEList = tEle.selectNodes("init/param");
							if (paramEList != null) {
								initParamMap = new HashMap<String, String>();
								for (Element ttEle : paramEList) {
									initParamMap.put(ttEle.attributeValue("name"), ttEle.attributeValue("value"));
								}
							}
							filterBeanList.add(new FilterBean(title, order, tEle.attributeValue("exceptionHandler"),
									initParamMap, tEle.attributeValue("class")));
							logger.info("启用过滤器" + title + ":\n	" + tEle.asXML());
						} else {
							logger.info("未启用过滤器" + title + "(enabled=false)\n	" + tEle.asXML());
						}
					}
				}
				// -----------------------------------------------------------------------------------解析服务端配置文件
				Element localEle = (Element) configDoc.getRootElement().selectSingleNode("local");
				if (localEle != null) {// 本地配置方式
					logger.info("bus running in configuration of local XML.");
					ins = new ConfigXmlImp(localEle);
				} else {
					Element remoteEle = (Element) configDoc.getRootElement().selectSingleNode("remote");
					if (remoteEle != null) {
						// //TODO
					}
				}
			} else {
				throw new BusRuntimeException(Constants.UserError.CONFIG_ERROR,
						"main configuration (bus-server.xml) could not be found in root of classpath and package net.butfly.bus.server.");
			}
		} catch (DocumentException _e) {
			throw new BusRuntimeException(Constants.UserError.CONFIG_ERROR, _e);
		}
	}

	public static String getServiceKey(TX tx) {
		return getServiceKey(tx.value(), tx.version());
	}

	public static String getServiceKey(String txCode, String versionNo) {
		return txCode + "-" + versionNo;
	}

	public static ServerConfigInterface getImpl() {
		if (ins == null) {
			init();
		}
		return ins;
	}

	// ---------------------------------------------------------------------------
	public static boolean isRunModeOfDebug() {
		return runMode.toUpperCase().equals("DEBUG");
	}

	public static boolean isSimulate() {
		return mode.equals("SIMULATE");
	}

	public static String getSimulateDir() {
		return simulateDir;
	}

	public static List<FilterBean> getFilterBeanList() {
		return filterBeanList;
	}

	public static String getTxAnnotation() {
		return txAnnotation;
	}

	public static String getDefaultErrorCode() {
		return defaultErrorCode;
	}

	// ---------------------------------------------------------------------------

	public static NodeBean getNodeBean(String nodeId) {
		return getImpl().getNodeBean(nodeId);
	}

	public static String[] getNodeIdsByTxMatching(String txCode) {
		return getImpl().getNodeIDsByMatching(txCode);
	}

	public static TxBean getTxBean(String code, String version) {
		return getImpl().getTxBean(code, version);
	}

	public static TimeoutBean getTimeoutBean(String code) {
		return getImpl().getTimeoutBean(code);
	}

	public static RouterBean getRouterBean() {
		return getImpl().getRouterBean();
	}

}
